package com.fengye.serialization.serializer.impl;

import com.dyuproject.protostuff.LinkedBuffer;
import com.dyuproject.protostuff.ProtostuffIOUtil;
import com.dyuproject.protostuff.Schema;
import com.dyuproject.protostuff.runtime.RuntimeSchema;
import com.fengye.serialization.serializer.Serializer;
import com.google.common.collect.Maps;

import java.util.Map;

/**
 * @Author fengye
 * @Date 2023/2/13 10:37
 **/
public class ProtoStuffSerializer implements Serializer {

    private static Map<Class<?>, Schema<?>> cacheSchema = Maps.newConcurrentMap();

    private static <T> Schema<T> getSchema(Class<T> clazz) {
        Schema<T> schema = (Schema<T>) cacheSchema.get(clazz);
        if(schema == null) {
            schema = RuntimeSchema.createFrom(clazz);
            cacheSchema.put(clazz, schema);
        }
        return schema;
    }

    @Override
    public <T> byte[] serialize(T obj) throws Exception {
        if(obj == null) {
            return new byte[0];
        }
        Class<T> clazz = (Class<T>) obj.getClass();
        LinkedBuffer buffer = LinkedBuffer.allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE);
        Schema<T> schema = getSchema(clazz);
        byte[] bytes = ProtostuffIOUtil.toByteArray(obj, schema, buffer);
        buffer.clear();
        return bytes;
    }

    @Override
    public <T> T deserialize(byte[] data, Class<T> clazz) throws Exception {
        if(data == null) {
            return null;
        }
        T result = (T) clazz.getConstructors()[0].newInstance();
        Schema<T> schema = getSchema(clazz);
        ProtostuffIOUtil.mergeFrom(data, result, schema);
        return result;
    }
}
